#pragma once

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

#include "Sem.hpp"
#include "Mutex.hpp"

namespace RingBufferModule
{
    using namespace SemModule;
    using namespace LockModule;

    template<typename T>
    class RingBuffer 
    {
    public:
        RingBuffer(int capa)
            :_ring(capa)
            ,_capa(capa)
            ,_p_step(0)
            ,_c_step(0)
            ,_datasem(0)
            ,_spacesem(capa)
        {}

        void Equeue(const T &in)
        {
            //生产者
            _spacesem.P();

            {
                LockGuard lockguard(_p_lock);
                _ring[_p_step] = in; // 生产完毕！
                _p_step++;
                _p_step %= _capa; // 维持唤醒特性
            }

            _datasem.V();
        }

        void Pop(T *out)
        {
            //消费者
            _datasem.P();

            {
                LockGuard lockguard(_c_lock);
                *out = _ring[_c_step];
                _c_step++;
                _c_step %= _capa;
            }

            _spacesem.V();
        }

        ~RingBuffer()
        {}

    private:
        std::vector<T> _ring;  //环，临界资源
        int _capa;             //总容量
        int _p_step;           //生产者位置
        int _c_step;           //消费者位置

        Sem _datasem;        //数据信号量
        Sem _spacesem;       //空间信号量

        Mutex _p_lock;
        Mutex _c_lock;
    };

}